package com.diaohw.module.metadata.service.execute;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.diaohw.module.metadata.mapper.MetaItemMapper;
import com.diaohw.module.metadata.mapper.MetaRelationshipMapper;
import com.diaohw.module.metadata.mapper.MetaValMapper;
import com.diaohw.module.metadata.obj.entity.MetaDataDO;
import com.diaohw.module.metadata.obj.entity.MetaItemDO;
import com.diaohw.module.metadata.obj.entity.MetaRelationshipDO;
import com.diaohw.module.metadata.obj.entity.MetaValDO;
import com.diaohw.module.metadata.service.MetaDataService;
import com.diaohw.platform.common.util.JsonUtil;
import com.diaohw.platform.remote.metadata.obj.bo.ParamBO;
import jakarta.annotation.Resource;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class MetaDetailExecute {

    @Resource
    private MetaValMapper valMapper;
    @Resource
    private MetaDataService dataMapper;
    @Resource
    private MetaItemMapper itemMapper;

    @Resource
    private MetaRelationshipMapper relationMapper;


    public ParamBO execute(String dataId) {
        MetaValDO data = valMapper.selectById(dataId);

        List<MetaDataDO> list = dataMapper.list(Wrappers.<MetaDataDO>lambdaQuery()
                .eq(MetaDataDO::getDataId, dataId)
                .select(MetaDataDO::getMetaId, MetaDataDO::getRowId, MetaDataDO::getVal, MetaDataDO::getItemId, MetaDataDO::getLevel)
        );

        if (Boolean.TRUE.equals(data.getGroup())) {
            return group(data, list);
        }
        List<MetaItemDO> itemList = itemList(data.getTargetId());
        Map<String, Object> map = deserialization(itemList, list);
        return ParamBO.of(dataId, data.getTargetId(), data.getGroup(), map);
    }

    private ParamBO group(MetaValDO data, List<MetaDataDO> list) {

        List<MetaRelationshipDO> metaList = relationMapper.selectList(Wrappers.<MetaRelationshipDO>lambdaQuery().eq(MetaRelationshipDO::getGroupId, data.getTargetId()));

        Map<String, List<MetaDataDO>> collect = list.stream().collect(Collectors.groupingBy(MetaDataDO::getMetaId));
        Map<String, Object> row = new HashMap<>();
        for (MetaRelationshipDO relationship : metaList) {

            if (!collect.containsKey(relationship.getMetaId())) {
                continue;
            }
            List<MetaDataDO> rows = collect.get(relationship.getMetaId());
            List<MetaItemDO> itemList = itemList(relationship.getMetaId());

            if (relationship.isMultiple()) {
                Map<String, List<MetaDataDO>> rowMap = rows.stream().collect(Collectors.groupingBy(MetaDataDO::getRowId));

                List<Map<String, Object>> maps = rowMap.values().stream().map(l -> deserialization(itemList, l)).toList();
                row.put(relationship.getMetaCode(), maps);
                continue;
            }
            Map<String, Object> val = deserialization(itemList, rows);
            row.put(relationship.getMetaCode(), val);
        }

        return ParamBO.of(data.getId(), data.getTargetId(), data.getGroup(), row);

    }

    private Map<String, Object> deserialization(List<MetaItemDO> items, List<MetaDataDO> dataList) {

        Map<String, MetaDataDO> collect = dataList.stream().collect(Collectors.toMap(MetaDataDO::getId, e -> e));
        Map<String, List<MetaDataDO>> rowMap = dataList.stream().collect(Collectors.groupingBy(MetaDataDO::getRowId));

        Map<String, Object> row = new HashMap<>();
        for (MetaItemDO item : items) {
            MetaDataDO data = collect.get(item.getId());
            String val = data.getVal();
            if (item.isMultiple()) {

                switch (item.getDataType()) {
                    case FLOAT -> row.put(item.getItemCode(), JsonUtil.toList(val, Double.class));
                    case INTEGER -> row.put(item.getItemCode(), JsonUtil.toList(val, Integer.class));
                    case BOOLEAN -> row.put(item.getItemCode(), JsonUtil.toList(val, Boolean.class));
                    case DATETIME -> row.put(item.getItemCode(), JsonUtil.toList(val, Date.class));
                    case TIME, DATE, STRING, ENUM -> row.put(item.getItemCode(), JsonUtil.toList(val, String.class));
                    case OBJECT -> {
                        List<String> list = JsonUtil.toList(val, String.class);
                        List<MetaItemDO> itemList = itemList(item.getDefaultVal());
                        List<Map<String, Object>> vals = list.stream().filter(rowMap::containsKey).map(rowMap::get).map(l -> deserialization(itemList, l)).toList();
                        row.put(item.getItemCode(), vals);
                    }
                }
                continue;
            }

            switch (item.getDataType()) {
                case FLOAT -> row.put(item.getItemCode(), JsonUtil.toBean(val, Double.class));
                case INTEGER -> row.put(item.getItemCode(), JsonUtil.toBean(val, Integer.class));
                case BOOLEAN -> row.put(item.getItemCode(), JsonUtil.toBean(val, Boolean.class));
                case DATETIME -> row.put(item.getItemCode(), JsonUtil.toBean(val, Date.class));
                case TIME, DATE, STRING, ENUM -> row.put(item.getItemCode(), val);
                case OBJECT -> {
                    List<MetaItemDO> itemList = itemList(item.getDefaultVal());
                    if (rowMap.containsKey(item.getItemCode())) {
                        Map<String, Object> process = deserialization(itemList, rowMap.get(val));
                        row.put(item.getItemCode(), process);
                    }
                }
            }

        }

        return row;
    }


    private List<MetaItemDO> itemList(String metaId) {
        return itemMapper.selectList(Wrappers.<MetaItemDO>lambdaQuery().eq(MetaItemDO::getMetaId, metaId));
    }

}
